package com.zjw.zy.componse.demo.base;


import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.widget.FrameLayout;
import android.widget.VideoView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author ：zhong.jw
 * @date ：Created in 2023/3/2 11:23
 */
public abstract class BaseSlideView extends FrameLayout {

    private static final String TAG = "BaseSlideView";

    private final VideoView mVideo1 = new VideoView(getContext());
    private final VideoView mVideo2 = new VideoView(getContext());
    private final VideoView mVideo3 = new VideoView(getContext());
    private final FrameLayout.LayoutParams mVideoVIewLayoutParams = new FrameLayout.LayoutParams(-1, -1);

    private final Handler uiHandler = new Handler(Looper.getMainLooper());
    private final VelocityTracker velocityTracker = VelocityTracker.obtain();

    private ExecutorService ioThreadPool;
    private float pointDownY = 0;

    //偶数表示mVideo1为当前视图，否则 mVideo2
    private int mCurrentVideoId = 0;

    //三指针，用来控制view位置关系
    @NonNull
    private VideoView pLastView = mVideo1;
    @NonNull
    private VideoView pCurrentView = mVideo2;
    @NonNull
    private VideoView pNextView = mVideo3;

    //视频流数据
    private Uri lastUri;

    private Uri currentUri;
    private Uri nextUri;

    @Nullable
    private ValueAnimator slideAnimation;

    public BaseSlideView(Context context) {
        super(context);
        initChildView();
    }

    public BaseSlideView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public BaseSlideView(Context context, AttributeSet attrs, int defStyleAttr, VideoView mVideo1) {
        super(context, attrs, defStyleAttr);
    }

    public BaseSlideView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }


    private void initChildView() {
        this.addView(mVideo3, mVideoVIewLayoutParams);
        this.addView(mVideo1, mVideoVIewLayoutParams);
        this.addView(mVideo2, mVideoVIewLayoutParams);
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        ioThreadPool = Executors.newSingleThreadExecutor();
        prepareData(true);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return true;
    }


    public void start() {
        this.pCurrentView.start();
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        Log.d(TAG, "onTouchEvent: " + action);

        float currentMoveY = event.getY();
        if (action == MotionEvent.ACTION_DOWN) {
            pointDownY = currentMoveY;
            velocityTracker.clear();
        }

        if (action == MotionEvent.ACTION_MOVE) {
            float moveDistance = currentMoveY - pointDownY;
            if (moveDistance < 0 && onHasNext(mCurrentVideoId)) {
                //上滑,下一条视频
                pCurrentView.setTranslationY(moveDistance);
                pNextView.setTranslationY(getMeasuredHeight() + moveDistance);
                velocityTracker.addMovement(event);
            } else if (moveDistance > 0 && mCurrentVideoId > 0) {
                //下滑
                pCurrentView.setTranslationY(moveDistance);
                pLastView.setTranslationY(-getMeasuredHeight() + moveDistance);
                velocityTracker.addMovement(event);
            }
        }

        if (action == MotionEvent.ACTION_UP) {
            //优先速度计算
            velocityTracker.addMovement(event);
            velocityTracker.computeCurrentVelocity(1000);
            float moveDistance = currentMoveY - pointDownY;
            float yVelocity = velocityTracker.getYVelocity();
            Log.d(TAG, "yVelocity = [" + yVelocity + "]");
            if (yVelocity <= -1000) {
                //上滑
                nextSlide();
            } else if (yVelocity >= 1000) {
                //下滑
                lastSlide();
            } else {
                int measuredHeight = getMeasuredHeight();
                boolean isRestore = Math.abs(moveDistance) <= measuredHeight * 0.3;
                if (isRestore) {
                    //还原
                    restoreSlide(moveDistance < 0);
                    return true;
                }

                if (moveDistance < 0) {
                    //上滑
                    nextSlide();
                } else {
                    //下滑
                    lastSlide();
                }
            }
        }
        return true;
    }

    private void lastSlide() {
        Log.d(TAG, "lastSlide() called");
        if (mCurrentVideoId <= 0) {
            restoreSlide(false);
            return;
        }
        int measuredHeight = getMeasuredHeight();
        slideAnimation = ValueAnimator.ofFloat(pCurrentView.getTranslationY(), measuredHeight);
        slideAnimation.addUpdateListener(animation -> {
            Float value = (Float) animation.getAnimatedValue();
            pCurrentView.setTranslationY(value);
            pLastView.setTranslationY(value - measuredHeight);
            pNextView.setTranslationY(value + measuredHeight);
            if (animation.getAnimatedFraction() == 1f) {
                onFinishSlided(false);
            }
        });
        slideAnimation.setDuration(200L);
        slideAnimation.start();
    }

    private void nextSlide() {
        Log.d(TAG, "nextSlide() called");
        if (!onHasNext(mCurrentVideoId)) {
            restoreSlide(true);
            return;
        }
        int measuredHeight = getMeasuredHeight();
        slideAnimation = ValueAnimator.ofFloat(pCurrentView.getTranslationY(), -measuredHeight);
        slideAnimation.addUpdateListener(animation -> {
            Float value = (Float) animation.getAnimatedValue();
            pCurrentView.setTranslationY(value);
            pNextView.setTranslationY(value + measuredHeight);
            pLastView.setTranslationY(value - measuredHeight);
            if (animation.getAnimatedFraction() == 1f) {
                onFinishSlided(true);
            }
        });
        slideAnimation.setDuration(200L);
        slideAnimation.start();
    }

    private void restoreSlide(boolean isNext) {
        Log.d(TAG, "restoreSlide() called " + isNext);
        int measuredHeight = getMeasuredHeight();
        slideAnimation = ValueAnimator.ofFloat(pCurrentView.getTranslationY(), 0);
        slideAnimation.addUpdateListener(animation -> {
            Float value = (Float) animation.getAnimatedValue();
            pCurrentView.setTranslationY(value);
            if (isNext) {
                pNextView.setTranslationY(value + measuredHeight);
            } else {
                pLastView.setTranslationY(value - measuredHeight);
            }
        });
        slideAnimation.setDuration(200L);
        slideAnimation.start();
    }

    private void onFinishSlided(boolean isNext) {
        if (isNext) {
            mCurrentVideoId++;

            VideoView pt = pCurrentView;
            pCurrentView = pNextView;
            pNextView = pt;
        } else {
            mCurrentVideoId--;

            VideoView pt = pCurrentView;
            pCurrentView = pLastView;
            pLastView = pt;
        }
        //播放
        onCurrentVideoStartPlay(pCurrentView);
        prepareData(isNext);
    }

    protected void onCurrentVideoStartPlay(@NonNull VideoView video) {
        video.start();
    }

    private void prepareData(boolean isNext) {
        ioThreadPool.execute(() -> {
            if (currentUri == null) {
                currentUri = onRequestUriData(mCurrentVideoId);
                nextUri = onRequestUriData(mCurrentVideoId + 1);
                uiHandler.post(() -> {
                    pCurrentView.setVideoURI(currentUri);
                    pCurrentView.start();
                    pNextView.setVideoURI(nextUri);
                });
                return;
            }

            if (isNext) {
                lastUri = currentUri;
                currentUri = nextUri;
                nextUri = onRequestUriData(mCurrentVideoId + 1);
            } else {
                nextUri = currentUri;
                currentUri = lastUri;
                lastUri = onRequestUriData(mCurrentVideoId - 1);
            }

            uiHandler.post(() -> {
                pNextView.setVideoURI(nextUri);
                pLastView.setVideoURI(lastUri);
            });
        });
    }

    protected abstract Uri onRequestUriData(int id);

    protected abstract boolean onHasNext(int id);


    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (slideAnimation != null) {
            slideAnimation.cancel();
        }
        ioThreadPool.shutdownNow();
    }
}
